﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PointAsLine
{
    public class Polyline
    {
        public List<PointF2G> Points = new List<PointF2G>();
        public int GroupIndex = -1;
        public double Area { get;private set; }
        public bool IsFinallyPolygon { get; set; } = false;

        public Polyline() { }
        public Polyline(Polyline seg2)
        {
            Points.AddRange(seg2.Points);
            this.GroupIndex = seg2.GroupIndex;
        }

        public int Count { get { return Points.Count; } }
        public PointF2G this[int index]
        {
            get { return Points[index]; }
        }

        public double CalculateSegmentLength()
        {
            if (Points == null || Points.Count < 2)
            {
                // 如果线段没有点或只有一个点，长度为0
                return 0.0;
            }

            double length = 0.0;

            // 遍历线段中的所有点，计算相邻点之间的距离并累加
            for (int i = 1; i < Points.Count; i++)
            {
                PointF2G prevPoint = Points[i - 1];
                PointF2G currentPoint = Points[i];

                // 计算两点之间的欧几里得距离
                double dx = currentPoint.X - prevPoint.X;
                double dy = currentPoint.Y - prevPoint.Y;
                length += Math.Sqrt(dx * dx + dy * dy);
            }

            return length;
        }

        internal void Add(PointF2G value)
        {
            Points.Add(value);
        }

        internal void RemoveAt(int i)
        {
            Points.RemoveAt(i);
        }

        internal void Insert(int v, PointF2G pointF2G)
        {
            this.Points.Insert(v, pointF2G);
        }

        internal void AddRange(Polyline seg2)
        {
            this.Points.AddRange(seg2.Points);
        }

        public double ComputeArea()
        {
            if (Points == null || Points.Count < 3)
            {
                // 至少需要 3 个点才能构成多边形
                return 0f;
            }

            float area = 0f;

            // 使用 Shoelace 公式计算面积
            int n = Points.Count;
            for (int i = 0; i < n; i++)
            {
                int j = (i + 1) % n; // 下一个点（循环回到第一个点）
                area += Points[i].X * Points[j].Y;
                area -= Points[i].Y * Points[j].X;
            }

            // 取绝对值并除以 2
            area = Math.Abs(area) / 2f;

            Area = area;
            return area;
        }

        /// <summary>
        /// 获取多边形的边界框
        /// </summary>
        public RectangleF GetBoundingBox()
        {
            float minX = float.MaxValue, minY = float.MaxValue;
            float maxX = float.MinValue, maxY = float.MinValue;

            foreach (var point in Points)
            {
                minX = Math.Min(minX, point.X);
                minY = Math.Min(minY, point.Y);
                maxX = Math.Max(maxX, point.X);
                maxY = Math.Max(maxY, point.Y);
            }

            return new RectangleF(minX, minY, maxX - minX, maxY - minY);
        }

        /// <summary>
        /// 判断点是否在多边形内部
        /// </summary>
        public bool IsPointInPolygon(PointF2G point)
        {
            // 射线法判断点是否在多边形内
            bool inside = false;
            int n = this.Count;

            for (int i = 0, j = n - 1; i < n; j = i++)
            {
                if (((this[i].Y > point.Y) != (this[j].Y > point.Y)) &&
                    (point.X < (this[j].X - this[i].X) * (point.Y - this[i].Y) / (this[j].Y - this[i].Y) + this[i].X))
                {
                    inside = !inside;
                }
            }

            return inside;
        }
    }

    class PolylineComparerByArea : IComparer<Polyline>
    {
        public int Compare(Polyline? x, Polyline? y)
        {
            return x.Area.CompareTo(y.Area) * -1;
        }
    }
}
